import copy
# import datetime
import os
import zipfile
import json
import requests

import unittest
import config
os.environ["CRYPTOGRAPHY_OPENSSL_NO_LEGACY"] = "1"
from log import train_log_config

LOGGER = train_log_config()

class PlatformAPIHandler:
    @staticmethod
    def pack_to_zip(directory=r"C:\algorithmProject\cement_ingredients_sub_model\service",
                    zip_file=r"C:\algorithmProject\cement_ingredients_sub_model\service\model.zip"):
        """
            将directory下的所有内容打包成zip
        :param directory: 需要打包的根目录的绝对路径
        :param zip_file: zip包的存放位置
        :return: True / False 表示是否成功存储 
        """
        LOGGER.info(f"\n****进入pack_to_zip(directory={directory},zip_file={zip_file})")
        try:
            with zipfile.ZipFile(zip_file, 'w', zipfile.ZIP_DEFLATED) as zipf:
                for root, dirs, files in os.walk(directory):
                    for file in files:
                        file_path = os.path.join(root, file)
                        if file_path.find('__pycache__') < 0 and file_path.find('resources') < 0 and file_path.find('zip') < 0:

                            zipf.write(file_path, os.path.relpath(file_path, directory))
            LOGGER.info(f"****打包成功")
            return True
        except Exception as e:
            LOGGER.info("****打包失败\n失败信息:\t", e.args)
            return False

    @staticmethod
    def _check_fix_url(url):
        url_str = copy.deepcopy(url)
        if not str(url).startswith('http'):
            url_str = "http://" + url
        if str(url_str).find('"') > 0:
            url_str = str(url_str).replace('"', "")
        # LOGGER.info(f"\n****返回_check_fix_url(url={url}),result={url_str}")
        return url_str

    @staticmethod
    def _query_model_code_from_platform(model_code='cement_batching_general_model',
                                        api_url="product-qa.allintechinc.com/machine-learning/api/v3/model/",
                                        ):
        api_url = PlatformAPIHandler._check_fix_url(api_url)
        header = {'current_tenant_id': "1"}
        response = requests.get(url=api_url + model_code,headers=header)
        if response.status_code != 200:
            LOGGER.info(f"调用失败，状态码{response.status_code}")
            return False, response
        else:
            if response.json()['data'] is not None:  # 这里未查询成功也是返回success
                LOGGER.info(f"调用成功，返回信息: \n {response.json()}")
                return True, response
            LOGGER.info(f"在查询接口，没有模型信息，新建模型: \n {response.json()}")
            return False, response

    @staticmethod
    def _upload_file_to_platform(params, file, api_url="product-qa.allintechinc.com/machine-learning/api/v2/model_import/custom/model"):
        api_url = PlatformAPIHandler._check_fix_url(api_url)
        LOGGER.info(f"模型上传接口(params={params},file={file},api_url={api_url})")
        header = {'current_tenant_id': config.current_tenant_id,'tenantId':config.current_tenant_id}
        response = requests.post(api_url, files=file, data=params,headers = header)
        if response.status_code != 200:
            LOGGER.info(f"调用失败，接口返回状态码{response.status_code}")
            return False, response
        else:
            if response.json()['status'] == 'success':
                LOGGER.info(f"调用成功，返回信息:  {response.json()}")
                return True, response
            LOGGER.info(f"调用失败，返回信息:  {response.json()}")
            return False, response

    @staticmethod
    def _register_new_version_info_to_platform(params, api_url="product-qa.allintechinc.com/machine-learning/api/v2/model_import/custom"):
        api_url = PlatformAPIHandler._check_fix_url(api_url)
        LOGGER.info(f"注册模型到平台(params={params},api_url={api_url})")
        header = {'Content-Type': 'application/json;charset=UTF-8','current_tenant_id': config.current_tenant_id,'tenantId':config.current_tenant_id}
        response = requests.post(api_url, data=params, headers=header)
        if response.status_code != 200:
            LOGGER.info(f"调用失败,状态码{response.status_code}")
            return False, response
        else:
            if response.json()['status'] == 'success':
                LOGGER.info(f"调用成功，返回信息: \n {response.json()}")
                return True, response
            LOGGER.info(f"调用失败，返回信息: \n {response.json()}")
            return False, response

    @staticmethod
    def register_new_version_to_platform(directory_need_zip=r"C:\algorithmProject\cement_ingredients_sub_model\service",
                                         zip_file_path=r"C:\algorithmProject\cement_ingredients_sub_model\service\model.zip",
                                         model_code='CI_10001162-CI_10001073-CI_10001091',  #model_code='CI_10001194-CI_10001073-CI_10001091'
                                         query_api="product-qa.allintechinc.com/machine-learning/api/v3/model/",
                                         upload_api="product-qa.allintechinc.com/machine-learning/api/v2/model_import/custom/model",
                                         register_api="product-qa.allintechinc.com/machine-learning/api/v2/model_import/custom",
                                         model_big_version=1,
                                         model_mini_version='0.0_20240407',
                                         model_name="cement_batching_normal_model",
                                         # model_descibre={'po425':'1.0.0','po325':'1.0.0'} # 预留字段，多品种时启用
                                         ):
        # 93   -->  91
        model_exists, query_result = PlatformAPIHandler._query_model_code_from_platform(model_code=model_code, api_url=query_api)  # 依据model_code查询model_id
        if model_exists:
            platform_model_id = query_result.json()['data']['id']
            is_creating = False
        else:
            platform_model_id = ''
            is_creating = True

        params = {'modelType': 'NORMAL', 'modelId': platform_model_id}  # 其他需要发送的参数
        files = {'file': open(zip_file_path, 'rb')}
        upload_success, response = PlatformAPIHandler._upload_file_to_platform(params, files, api_url=upload_api)
        if not upload_success:
            raise Exception(f"调用文件上传接口失败,返回{response}")

        params = response.json()['data']
        mini_version = {}
        data = {
            'modelName': params['modelName'] if params['modelName'] is not None else model_name,
            'modelId': params['modelId'],
            'parentId': 0,
            'open': True,
            'description': str(mini_version),
            'modelVersionId': params['modelVersionId'],
            'modelFlag': params['modelFlag'],
            'create': True if is_creating else False,
            'modelVersion': model_big_version,
            'miniVersion': str(model_big_version) + '.' + model_mini_version,
            'modelType': 'NORMAL',
            'userName': '水泥配料子模型独立引擎'
        }
        register_success, response = PlatformAPIHandler._register_new_version_info_to_platform(json.dumps(data), register_api)
        if not register_success:
            raise Exception(f"调用注册接口失败,返回{response.status_code}")
            return False
        else:
            LOGGER.info("register_new_version_to_platform成功注册")
            return True

    @staticmethod
    def develop_in_platform(model_code='CI_10001162-CI_10001073-CI_10001091',
                            model_version=None,
                            develop_type='LOCAL',  # LOCAL : 本地部署  PROD : 生产部署
                            api_url="product-qa.allintechinc.com/machine-learning/api/v1/model/auto/deploy"):
        api_url = PlatformAPIHandler._check_fix_url(api_url)
        LOGGER.info(f"部署(model_code={model_code}, model_version={model_version}, develop_type={develop_type},api_url={api_url}")
        header = {'Content-Type': 'application/json;charset=UTF-8','current_tenant_id': config.current_tenant_id,'tenantId':config.current_tenant_id}
        if model_version is None:
            response = requests.post(api_url, data=json.dumps({'modelCode': model_code, 'deployPolicy': develop_type}), headers=header)
        else:
            response = requests.post(api_url, data=json.dumps({'modelCode': model_code, 'modelVersion': model_version, 'deployPolicy': develop_type}), headers=header)

        if response.status_code != 200:
            LOGGER.info(f"调用部署接口失败，状态码{response.status_code}")
            return False
        else:
            if response.json()['status'] == 'success':
                LOGGER.info(f"调用成功，返回信息:  {response.json()}")
                return True, response
            LOGGER.info(f"调用失败，返回信息: {response.json()}")
            return False, response


class PlatformAPIHandlerTestCase(unittest.TestCase):  # 单元测试第一步，继承unittest类
    def test_pack_to_zip(self):
        directory = r"C:\algorithmProject\cement_ingredients_sub_model\service"
        zip_file = r"C:\algorithmProject\cement_ingredients_sub_model\service\model.zip"
        if os.path.exists(zip_file):
            os.remove(zip_file)
        PlatformAPIHandler.pack_to_zip(directory, zip_file)
        assert os.path.exists(zip_file), "Zip文件未生成"  # 是否成功打包
        with zipfile.ZipFile(zip_file, 'r') as zipf:
            assert "getModelFromGeneral.py" in zipf.namelist(), "文件 py 未包含在zip中"
            assert any(str(name).find(r'log\\') < 0 for name in zipf.namelist()), "目录 log 未包含在zip中"
            assert "model_desc.json" in zipf.namelist(), "文件 json 未包含在zip中"

    def test_register_new_version_to_platform(self):
        result = PlatformAPIHandler.register_new_version_to_platform(directory_need_zip=r"C:\algorithmProject\cement_ingredients_sub_model\service",
                                                                     zip_file_path=r"C:\algorithmProject\cement_ingredients_sub_model\service\model.zip",
                                                                     model_code='CI_10001162-CI_10001073-CI_10001091',
                                                                     query_api="product-qa.allintechinc.com/machine-learning/api/v3/model/",
                                                                     upload_api="product-qa.allintechinc.com/machine-learning/api/v2/model_import/custom/model",
                                                                     register_api="product-qa.allintechinc.com/machine-learning/api/v2/model_import/custom",
                                                                     model_big_version=1,
                                                                     model_mini_version='1.2_20240407',
                                                                     model_name="cement_batching_normal_model",
                                                                     # model_descibre={'po425':'1.0.0','po325':'1.0.0'} # 预留字段，多品种时启用
                                                                     )
        assert result, "注册失败"

    def test_develop_in_platform(self):
        local_result = PlatformAPIHandler.develop_in_platform(model_code='CI_10001162-CI_10001073-CI_10001091', model_version='1.1.1_20240403',
                                                              develop_type='LOCAL',
                                                              api_url="product-qa.allintechinc.com/machine-learning/api/v1/model/auto/deploy")
        prod_result = PlatformAPIHandler.develop_in_platform(model_code='CI_10001162-CI_10001073-CI_10001091', develop_type='PROD', model_version='1.1.1_20240403',
                                                             api_url="product-qa.allintechinc.com/machine-learning/api/v1/model/auto/deploy")
        assert local_result & prod_result, "部署失败"


if __name__ == '__main__':
    unittest.main()
